﻿using NicoView.Model.Service.Results;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace NicoView.Model.Service
{
    /// <summary>
    /// ユーザ情報を管理するマネージャ
    /// </summary>
    public sealed class NicoUserApiInfoSetRequestManager:IDisposable
    {
        private Dictionary<NotificationNicoUser, NotificationNicoUser> requestList;

        private NicoServiceApplicationInstance application;

        private Task requestTask;

        private AutoResetEvent requestAddEvent;

        private AutoResetEvent disposeRequest;


        private int _dirayTime;

        internal NicoUserApiInfoSetRequestManager(NicoServiceApplicationInstance application)
        {
            this.requestList = new Dictionary<NotificationNicoUser, NotificationNicoUser>();
            this.application = application;
            this.requestAddEvent = new AutoResetEvent(false);
            this.disposeRequest = new AutoResetEvent(false);

            _dirayTime = 0;
#if USE_TASKLOOP
            requestTask = Task.Factory.StartNew(async () =>
            {
                do{
                    switch (EventWaitHandle.WaitAny(new WaitHandle[] { requestAddEvent, disposeRequest }))
                    {

                        case 0:

                           
                            try
                            {
                                while (requestList.Count > 0)
                                {
                                    try
                                    {
                                        KeyValuePair<NotificationNicoUser, NotificationNicoUser> user;
                                        lock (requestList)
                                        {
                                            user = requestList.First();
                                        }

                                        var result = await _setUserApiInfo(user.Value);
                                        if (result.Succeed == false) _dirayTime++;
                                        await Task.Delay(TimeSpan.FromSeconds(_dirayTime));

                                        lock (requestList)
                                        {
                                            requestList.Remove(user.Key);

                                        }
                                    }
                                    catch
                                    {

                                    }
                                    
                                }
                            
                               
                                


                            }
                            finally
                            {
                                requestAddEvent.Reset();
                            }
                            break;

                        case 1:
                            return;

                    }
                }while(true);


             });

#endif
            
        }


        /// <summary>
        /// ユーザ情報にAPI情報を割り当てるよう要求
        /// </summary>
        /// <param name="user"></param>
        public  void SetUserApiInfoRequest(NotificationNicoUser user)
        {
#if USE_TASKLOOP

            
            lock (requestList)
            {
                if (requestList.ContainsKey(user)) return;
                requestList.Add(user, user);
            }

            
            requestAddEvent.Set();

#else

            await _setUserApiInfo(user);

#endif




        }


        private async Task<IResult> _setUserApiInfo(NotificationNicoUser user)
        {

            


            try
            {
                await this.application.SetApiUserInfo(user);
            }
            catch (Exception e)
            {
                application.BaseApplication.OnNotifyWaning(e, "ユーザ情報取得APIに接続できませんでした");
                   
            }

            if (user.IsSetApiInfo())
            {

                return _setUserSucceedResult;

            }

            else
            {

                return _setUserFailedResult;

            }

        }


        private static readonly IResult _setUserSucceedResult = new Result();

        private static readonly IResult _setUserFailedResult = new Result(false, "ユーザ情報取得に失敗しました");

        /// <summary>
        /// このオブジェクトに割り当てられているリソースをすべて解放
        /// </summary>
        public void Dispose()
        {
            disposeRequest.Set();
        }
    }
}
